﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;

namespace Moonwish.Silverlight.Controls
{
    /// <summary>
    /// 下拉树控件by zhlin 2011-06-17
    /// </summary>
    [TemplatePart(Name = "SelectedDisplay", Type = typeof(ContentControl))]
    [TemplatePart(Name = "DropArrow", Type = typeof(Border))]
    [TemplatePart(Name = "ExpanderContainer", Type = typeof(Popup))]
    public class DropTreeView : SmartTreeView
    {
        private Popup _expanderContainer;
        private Border _dropArrow;
        private ContentControl _selectedDisplay;
        private ScrollViewer _scrollView;
        private Canvas _outsideCanvas;
        private Canvas _popupContentCanvas;
        public new event RoutedPropertyChangedEventHandler<object> SelectedItemChanged;
        public event EventHandler DropDownOpened;

        public DropTreeView()
        {
            DefaultStyleKey = typeof(DropTreeView);
        }

        /// <summary>
        /// 下拉内容高度。
        /// </summary>
        public double RenderHeight
        {
            get;
            set;
        }

        /// <summary>
        /// 选择项显示模版
        /// </summary>
        public DataTemplate CaptionDisplayTemplate
        {
            get;
            set;
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            _expanderContainer = (Popup)GetTemplateChild("ExpanderContainer");

            _scrollView = (ScrollViewer)_expanderContainer.Child;

            _dropArrow = (Border)GetTemplateChild("DropArrow");

            _selectedDisplay = (ContentControl)GetTemplateChild("SelectedDisplay");

            MouseLeftButtonUp += ShowPopup;

            _dropArrow.MouseMove += GotoMouseMove;

            _selectedDisplay.ContentTemplate = CaptionDisplayTemplate ?? DefaultSelectedDisplayTemplate;
            _selectedDisplay.DataContext = SelectedItemDelayed;

            SetItemSelected += DropTreeView_SetItemSelected;

            _popupContentCanvas = new Canvas();

            _outsideCanvas = new Canvas();
            _outsideCanvas.MouseLeftButtonUp += delegate { _expanderContainer.IsOpen = false; };
            _outsideCanvas.Background = new SolidColorBrush(Colors.Transparent);

            _expanderContainer.Child = _popupContentCanvas;

            _popupContentCanvas.Children.Add(_outsideCanvas);
            _popupContentCanvas.Children.Add(_scrollView);

            _expanderContainer.Opened += ExpanderContainer_Opened;

            if (SelectedItemDelayed != null)
            {
                var e = new SetItemSelectedEventArgs();
                e.Item = SelectedItemDelayed;
                DropTreeView_SetItemSelected(e);
            }
        }

        void ExpanderContainer_Opened(object sender, EventArgs e)
        {
            if (DropDownOpened != null)
            {
                DropDownOpened(sender, e);
            }
        }

        private bool _isLoaded;
        void DropTreeView_SetItemSelected(SetItemSelectedEventArgs e)
        {
            _selectedDisplay.DataContext = SelectedItemDelayed;
            if (!_isLoaded)
            {
                _isLoaded = true;
                if (SelectedItemChanged != null)
                {
                    SelectedItemChanged(this, new RoutedPropertyChangedEventArgs<object>(null, SelectedItemDelayed));
                }
            }
        }

        private void GotoMouseMove(object sender, MouseEventArgs e)
        {
            VisualStateManager.GoToState(this, "MouseOver", true);
        }

        void ShowPopup(object sender, MouseEventArgs e)
        {
            _expanderContainer.IsOpen = !_expanderContainer.IsOpen;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            if (_scrollView != null)
            {
                if (!double.IsInfinity(availableSize.Width))
                {
                    _scrollView.Width = availableSize.Width;
                }
                if (RenderHeight > 100 && RenderHeight < 1000)
                {
                    _scrollView.MaxHeight = RenderHeight;
                }
            }
            if (_outsideCanvas != null)
            {
                ArrangePopup();
            }
            return base.MeasureOverride(availableSize);
        }

        private void ArrangePopup()
        {
            var transform = TransformToVisual(null);
            if (transform != null)
            {
                var content = Application.Current.Host.Content;
                _outsideCanvas.Width = content.ActualWidth;
                _outsideCanvas.Height = content.ActualHeight;

                var point = new Point(0.0, 0.0);

                var point2 = new Point(1.0, 0.0);

                var point3 = new Point(0.0, 1.0);

                var point4 = transform.Transform(point);

                var point5 = transform.Transform(point2);

                var point6 = transform.Transform(point3);

                var identity = Matrix.Identity;

                identity.M11 = point5.X - point4.X;

                identity.M12 = point5.Y - point4.Y;

                identity.M21 = point6.X - point4.X;

                identity.M22 = point6.Y - point4.Y;

                identity.OffsetX -= point4.X;

                identity.OffsetY -= point4.Y;

                var transform2 = new MatrixTransform

                                     {

                                         Matrix = identity

                                     };
                _outsideCanvas.RenderTransform = transform2;
            }
        }

        protected override void OnSelectedItemChanged(RoutedPropertyChangedEventArgs<object> e)
        {
            if (_expanderContainer != null)
            {
                if (_expanderContainer.IsOpen && e.OldValue != null)
                {
                    _expanderContainer.IsOpen = false;
                    SelectedItem = e.NewValue;
                    if (SelectedItemChanged != null)
                    {
                        SelectedItemChanged(this, e);
                    }
                }
                else
                {
                    if (e.NewValue != SelectedItemDelayed)
                    {
                        SelectedItem = SelectedItemDelayed ?? e.NewValue;
                        _expanderContainer.IsOpen = false;
                    }
                }
                if (null != SelectedItemDelayed)
                {
                    _selectedDisplay.DataContext = SelectedItemDelayed;
                }
            }
        }

        protected DataTemplate DefaultSelectedDisplayTemplate
        {
            get
            {
                const string template =
            @"<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
            <Grid Background=""White"">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width=""16""></ColumnDefinition>
                    <ColumnDefinition Width=""*""></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Image x:Name=""imgTreeNode"" Source = ""{0}"" VerticalAlignment=""Center""/>
                <TextBlock Grid.Column=""1"" x:Name=""txtDisplayMember"" Margin=""5, 0, 0, 0"" VerticalAlignment=""Center"" Text=""{Binding ElementName=SelectedDisplay, Path=DataContext.{1}}"" />
            </Grid>
        </DataTemplate>";
                return (DataTemplate)XamlReader.Load(template.Replace("{0}", TreeNodeImagePath).Replace("{1}", DisplayMemberPath));
            }
        }
    }
}
